#include <lobi/thread.h>

#include <pthread.h>

class thread_imp : public thread_imp_base
{
	// thread object related data
	thread* client;
	void* data;

	// pthread api related data
	pthread_t thr_id;
	
	public:
		thread_imp() { client = 0; }
		~thread_imp() {}
		
		void set_client(thread* client_) { client = client_; }
		
		void set_data(void* data_) { data = data_; }
		void* get_data() { return data; }

		static void* entrypoint(void* thisptr_data)
		{
			/* Guarantees that thread resources are deallocated upon return */
			pthread_detach(pthread_self()); 

			thread_imp* p = (thread_imp*) thisptr_data;
			p->run(p->get_data());
		}

		bool start(void* data_)
		{
			set_data(data_);
			return pthread_create(&thr_id,NULL,entrypoint,this) == 0;
		}

		void run(void* data_)
		{
			client->execute(data_);
		}
};

thread::thread()
{
	imp = new thread_imp();
}

thread::~thread()
{
	delete imp;
}

bool thread::run(void* data)
{
	imp->set_client(this);
	return imp->start(data);
}


/*
 * class mutex
 */

class mutex_imp : public mutex_imp_base
{
	pthread_mutex_t pthread_mutex;

	public:
		mutex_imp() { if (pthread_mutex_init(&pthread_mutex, NULL) != 0) throw; }
		virtual ~mutex_imp() { pthread_mutex_destroy(&pthread_mutex); }

		void lock() { pthread_mutex_lock(&pthread_mutex); }
		void unlock() { pthread_mutex_unlock(&pthread_mutex); }
};
mutex::mutex() { imp = new mutex_imp(); }
mutex::~mutex() { delete imp; }
void mutex::lock() { imp->lock(); }
void mutex::unlock() { imp->unlock(); }
